<!DOCTYPE html>
<html>

<head>
    <title>写作内容推荐.ai</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.staticfile.net/bootstrap/5.3.2/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.staticfile.net/bootstrap/5.3.2/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdn.staticfile.net/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.net/tensorflow/4.16.0/tf.min.js"></script>
    <script src="https://cdn.staticfile.net/mathjs/12.3.0/math.min.js"></script>
    <script>let dataJson = []</script>
</head>

<body>

    <nav id="navbar" class="navbar navbar-expand-md bg-dark navbar-dark">
        <a class="navbar-brand btn" data-bs-toggle="modal" data-bs-target="#myModal">增加</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#collapsibleNavbar">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="collapsibleNavbar">
            <ul class="navbar-nav">
                <li class="nav-item dropdown">
                    <a class="nav-link btn dropdown-toggle text-white" id="navbardrop" data-bs-toggle="dropdown">
                        文件
                    </a>
                    <div class="dropdown-menu p-2">
                        <div class="input-group">
                            <span class="input-group-text btn btn-primary">恢复</span>
                            <input id="inputfile" type="file" class="form-control"
                                onchange="nb.handleFileUpload(event)">
                        </div>
                        <button type="button" class="btn btn-primary form-control mt-2"
                            onclick="nb.downloadJson()">备份</button>
                    </div>
                </li>
            </ul>
        </div>
        <span class="d-flex">
            <input id="file-name" class="form-control me-2" type="text">
        </span>
    </nav>
    <script>
        class navbar {
            constructor(name) {
                this.workshopname = name;
            }
            handleFileUpload(event) {
                const file = event.target.files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = (e) => {
                        try {
                            dataJson = JSON.parse(e.target.result);
                            cf.main();
                            tk.main();
                        } catch (error) {
                            console.error("无法解析JSON文件:", error);
                        }
                    };
                    reader.onerror = (e) => {
                        console.error("读取文件时出错:", e);
                    };
                    reader.readAsText(file);
                }
            }
            downloadJson() {
                if (dataJson.length > 0) {
                    let dateString = this.getCurrentDateString();
                    const jsonString = JSON.stringify(dataJson);
                    const blob = new Blob([jsonString], { type: 'application/json' });
                    const url = URL.createObjectURL(blob);
                    const link = document.createElement('a');
                    link.href = url;
                    link.setAttribute('download', '记录文档-' + dateString + '.json');
                    document.body.appendChild(link);
                    link.click();
                    document.body.removeChild(link);
                    console.log("成功下载文件：记录文档-" + dateString + ".json");
                } else {
                    console.log("列表无数据！");
                }
            }
            getCurrentDateString() {
                const now = new Date();
                const year = now.getFullYear();
                const month = String(now.getMonth() + 1).padStart(2, '0');
                const date = String(now.getDate()).padStart(2, '0');
                const currentDateString = `${year}-${month}-${date}`;
                return currentDateString;
            }
        }
        const nb = new navbar();
    </script>

    <!-- 模态框 -->
    <div class="modal" id="myModal">
        <div class="modal-dialog modal-lg"><!-- modal-sm modal-lg modal-xl modal-fullscreen -->
            <div class="modal-content">
                <!-- 模态框头部 -->
                <div class="modal-header">
                    <h4 class="modal-title">增加</h4>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <!-- 模态框内容 -->
                <div class="modal-body">
                    <textarea class="form-control p-3" rows="9"></textarea>
                </div>
                <!-- 模态框底部 -->
                <div class="modal-footer">
                    <button type="button" class="btn btn-primary" onclick="md.main()">增加</button>
                    <button type="button" class="btn btn-danger" data-bs-dismiss="modal">关闭</button>
                </div>
            </div>
        </div>
    </div>
    <script>
        class modalDialog {
            constructor(name) {
                this.workshopname = name;
            }
            splitByNewlines(str) {
                const regex = /[。？！\r\n]+/g;
                const parts = str.split(regex);
                return parts.map(e => e.trim()).filter(part => part !== '');
            }
            main() {
                let texts = this.splitByNewlines($("#myModal div div div.modal-body textarea").val());
                dataJson.push(texts);
                $("#myModal div div div.modal-body textarea").val("");
                cf.main();
            }
        }
        const md = new modalDialog();
    </script>

    <div id="container-fluid" class="container-fluid row">
        <div class="col-6 border" style="max-height: 800px;overflow: auto;">.col</div>
        <textarea class="col-6 p-3" rows="30" onchange="cf.textarea(this)"></textarea>
    </div>
    <script>
        class containerFluid {
            constructor(name) {
                this.workshopname = name;
                this.lastStr = "";
                this.uniqueCharsArray = [];
                this.maxLength = 0;
            }
            splitByPunctuationAndNewlines(str) {
                const regex = /[。？！\r\n]+/g;
                const parts = str.split(regex);
                return parts.map(e => e.trim()).filter(part => part !== '');
            }
            main(dj = dataJson) {
                if (dj.length > 0) {
                    for (let ti in dj) {
                        let htmlText = "", htmlTexts = "";
                        for (let index in dj[ti]) {
                            if (index == 0) {
                                htmlText = '<h5><span class="badge rounded-pill bg-info">' + ti + '</span>' + dj[ti][index] + '</h5>';
                            } else {
                                htmlText += '<p>' + dj[ti][index] + '</p>';
                            }
                        }
                        htmlTexts = `<div class="border" style="max-height: 300px;overflow: auto;">` + htmlText + `</div>`;
                        if (ti == 0) {
                            $("#container-fluid div:eq(0)").html(htmlTexts);
                        } else {
                            $("#container-fluid div:eq(0)").append(htmlTexts);
                        }
                    }
                } else { $("#container-fluid div").html(""); }
            }
            textarea(e) {
                let sStr = this.splitByPunctuationAndNewlines($(e).val());
                let last_string = "";
                sStr.forEach((e) => {
                    if (e.length > 5) {
                        last_string = e;
                    }
                });
                if (last_string != this.lastStr) {
                    this.lastStr = last_string;
                    tm.main(this.lastStr);
                }
            }
        }
        const cf = new containerFluid();
    </script>

    <script>

        class Tokenizer {
            constructor(name) {
                this.workshopname = name;
                this.uniqueCharsArray = [];
                this.maxLength = 0;
                this.input_ids = [];
                this.labels = [];
                this.attention_mask = [];
            }
            main() {
                this.input_mask_label().forEach((item) => {
                    this.input_ids.push(item.input), this.labels.push(item.label);
                });
                tm.createModel(this.uniqueCharsArray.length, dataJson.length);
                let x = tf.tensor(this.input_ids);
                let y = tf.tensor(this.labels);
                tm.Fit(x, y);
            }
            fit_on_texts(texts = dataJson) {
                let uniqueCharsArray = [];
                texts.forEach((paragraph) => {
                    paragraph.map((sentence) => {
                        this.maxLength = Math.max(this.maxLength, sentence.length);
                        for (let index in sentence) {
                            uniqueCharsArray.includes(sentence[index]) || uniqueCharsArray.push(sentence[index]);
                        }
                    });
                })
                let result = ["Null"].concat(this.shuffleArray(uniqueCharsArray).filter(part => part !== 'Null'));
                return result;
            }
            texts_to_sequences(texts, uniqueCharsArray) {
                let input_ids = [];
                for (let index in texts) {
                    input_ids.push(uniqueCharsArray.indexOf(texts[index]));
                }
                return input_ids;
            }
            sequences_to_texts(sequences, uniqueCharsArray) {
                let texts = [];
                for (let index in sequences) {
                    if (sequences[index] == 0) {
                        texts.push(uniqueCharsArray[sequences[index]]);
                    }
                }
                return [texts.join("")];
            }
            input_mask_label() {
                let output = [];
                let input = [], mask = [], label = [];
                this.uniqueCharsArray = this.fit_on_texts();
                dataJson.forEach((paragraph, pi) => {
                    paragraph.map((sentence) => {
                        if (sentence.length > 10) {
                            input = [], mask = [], label = [];
                            input = tf.zeros([this.uniqueCharsArray.length]).arraySync();
                            for (let index in sentence) {
                                input[this.uniqueCharsArray.indexOf(sentence[index])] = 1;
                            }
                            for (let i = 0; i < dataJson.length; i++) {
                                if (i == pi) {
                                    label.push(1);
                                } else {
                                    label.push(0);
                                }
                            }
                            output.push({ input: input, label: label });
                        }
                    });
                });
                return this.shuffleArray(output);
            }
            shuffleArray(array) {
                for (let i = array.length - 1; i > 0; i--) {
                    const j = Math.floor(Math.random() * (i + 1));
                    [array[i], array[j]] = [array[j], array[i]];
                }
                return array;
            }
            Statistics(texts = dataJson) {
                let maxLength = 0;
                texts.forEach((paragraph) => {
                    paragraph.map((sentence) => {
                        maxLength = Math.max(maxLength, sentence.length);
                    });
                })
                return [maxLength];
            }
        }
        const tk = new Tokenizer();

        class textsModel {
            constructor(name) {
                this.workshopname = name;
            }
            main(x) {
                let ts = tk.texts_to_sequences(x, tk.uniqueCharsArray);
                let input = tf.zeros([tk.uniqueCharsArray.length]).arraySync();
                for (let index in ts) {
                    input[ts[index]] = 1;
                }
                let ls = this.list_sort(this.Predict(tf.tensor(input).reshape([1, input.length])).squeeze().arraySync());
                let dj = [];
                ls.forEach((item) => {
                    dj.push(dataJson[item]);
                });
                cf.main(dj);
            }
            createModel(input_shape, output_shape) {
                this.model = tf.sequential();
                this.model.add(tf.layers.dense({ units: output_shape * 2, inputShape: [input_shape] }));
                this.model.add(tf.layers.dense({ units: output_shape, activation: 'softmax' }));
                this.model.compile({ optimizer: 'sgd', loss: 'meanSquaredError', metrics: ['accuracy'] });
                this.model.summary();
            }
            Predict(x) {
                const output = this.model.predict(x);
                return output;
            }
            async Fit(x, y) {
                for (let i = 0; i < 50; i++) {
                    const h = await this.model.fit(x, y, { epochs: 5, batchSize: 1 });
                    console.log(i, h.history.loss[0]);
                }
                tk.input_ids.map(async (item, index) => {
                    const tensor = this.Predict(tf.tensor(item).reshape([1, tk.uniqueCharsArray.length]));
                });
            }
            list_sort(array) {
                console.log(array);
                let arr = array.map((item, index) => { return { item: item, index: index } });
                arr.sort((a, b) => b.item - a.item);
                return arr.map((item) => { return item.index });
            }
        }
        const tm = new textsModel();

    </script>
</body>

</html>